﻿using System.ComponentModel;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace DesktopToyWpf.Views;

public class MoodSlider : Control
{
    private static readonly Type TypeOfThis = typeof(MoodSlider);
    private static MoodSlider GetView(DependencyObject d) => (MoodSlider)d;

    public MoodSlider()
    {
        SnapsToDevicePixels = true;
        Opacity = DEFAULT_OPACITY;
    }

    private static void RefreshUICallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        GetView(d).InvalidateVisual();
    }

    #region LargeRectangleColorProperty

    /// <summary>
    /// 刻度条上大矩形颜色
    /// </summary>
    [Category("心情条")]
    public SolidColorBrush LargeRectangleColor
    {
        get => (SolidColorBrush)GetValue(LargeRectangleColorProperty);
        set => SetValue(LargeRectangleColorProperty, value);
    }

    public static readonly DependencyProperty LargeRectangleColorProperty =
        DependencyProperty.Register(nameof(LargeRectangleColor), typeof(SolidColorBrush), TypeOfThis,
            new PropertyMetadata(Brushes.Black, RefreshUICallback));

    #endregion

    #region SmallRectangleColorProperty

    /// <summary>
    /// 刻度条上小矩形颜色
    /// </summary>
    [Category("心情条")]
    public SolidColorBrush SmallRectangleColor
    {
        get => (SolidColorBrush)GetValue(SmallRectangleColorProperty);
        set => SetValue(SmallRectangleColorProperty, value);
    }

    public static readonly DependencyProperty SmallRectangleColorProperty =
        DependencyProperty.Register(nameof(SmallRectangleColor), typeof(SolidColorBrush), TypeOfThis,
            new PropertyMetadata(Brushes.Black, RefreshUICallback));

    #endregion

    #region ThumbFillProperty

    /// <summary>
    /// 滑块背景色
    /// </summary>
    [Category("心情条")]
    public SolidColorBrush ThumbFill
    {
        get => (SolidColorBrush)GetValue(ThumbFillProperty);
        set => SetValue(ThumbFillProperty, value);
    }

    public static readonly DependencyProperty ThumbFillProperty =
        DependencyProperty.Register(nameof(ThumbFill), typeof(SolidColorBrush), TypeOfThis,
            new PropertyMetadata(Brushes.Black, RefreshUICallback));

    #endregion

    #region ThumbStrokeProperty

    /// <summary>
    /// 滑块边框颜色
    /// </summary>
    [Category("心情条")]
    public SolidColorBrush ThumbStroke
    {
        get => (SolidColorBrush)GetValue(ThumbStrokeProperty);
        set => SetValue(ThumbStrokeProperty, value);
    }

    public static readonly DependencyProperty ThumbStrokeProperty =
        DependencyProperty.Register(nameof(ThumbStroke), typeof(SolidColorBrush), TypeOfThis,
            new PropertyMetadata(Brushes.Black, RefreshUICallback));

    #endregion

    #region ThumbRadiusProperty

    /// <summary>
    /// 滑块半径
    /// </summary>
    [Category("心情条")]
    public double ThumbRadius
    {
        get => (double)GetValue(ThumbRadiusProperty);
        set => SetValue(ThumbRadiusProperty, value);
    }

    public static readonly DependencyProperty ThumbRadiusProperty =
        DependencyProperty.Register(nameof(ThumbRadius), typeof(double), TypeOfThis,
            new PropertyMetadata(0d, RefreshUICallback));

    #endregion

    #region ThumbStrokeLengthProperty

    /// <summary>
    /// 滑块描边尺寸
    /// </summary>
    [Category("心情条")]
    public double ThumbStrokeLength
    {
        get => (double)GetValue(ThumbStrokeLengthProperty);
        set => SetValue(ThumbStrokeLengthProperty, value);
    }

    public static readonly DependencyProperty ThumbStrokeLengthProperty =
        DependencyProperty.Register(nameof(ThumbStrokeLength), typeof(double), TypeOfThis,
            new PropertyMetadata(0d, RefreshUICallback));

    #endregion

    #region ValueProperty

    /// <summary>
    /// 当前心情
    /// </summary>
    [Category("心情条")]
    public int Value
    {
        get => (int)GetValue(ValueProperty);
        set => SetValue(ValueProperty, value);
    }

    public static readonly DependencyProperty ValueProperty =
        DependencyProperty.Register(nameof(Value), typeof(int), TypeOfThis,
            new PropertyMetadata(1, ValuePropertyChangedCallback));

    private static void ValuePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        RefreshUICallback(d ,e);
        GetView(d).RaiseValueChangedEvent((int)e.NewValue);
    }

    #endregion

    #region ValueChangedEvent

    public event RoutedEventHandler<int> ValueChanged
    {
        add => AddHandler(ValueChangedEvent, value);
        remove => RemoveHandler(ValueChangedEvent, value);
    }

    public static readonly RoutedEvent ValueChangedEvent =
        EventManager.RegisterRoutedEvent(
            nameof(ValueChanged),
            RoutingStrategy.Bubble,
            typeof(RoutedEventHandler<int>),
            TypeOfThis);

    private void RaiseValueChangedEvent(int data)
    {
        RaiseEvent(new RoutedEventArgs<int>(ValueChangedEvent, this, data));
    }

    #endregion

    

    protected override void OnRender(DrawingContext dc)
    {
        base.OnRender(dc);

        dc.DrawRectangle(Brushes.Transparent, null, new Rect(0, 0, ActualWidth, ActualHeight));

        var length = ActualWidth - ThumbRadius * 2;
        if (length <= 0) return;

        var point0 = new Point(ThumbRadius, ThumbRadius);
        var point1 = new Point(ThumbRadius + 0.25 * length, ThumbRadius);
        var point2 = new Point(ThumbRadius + 0.5 * length, ThumbRadius);
        var point3 = new Point(ThumbRadius + 0.75 * length, ThumbRadius);
        var point4 = new Point(ActualWidth - ThumbRadius, ThumbRadius);

        // 画刻度条
        DrawCenterRectangle(dc, point0, new Size(4d, 18d), LargeRectangleColor);
        DrawCenterRectangle(dc, point1, new Size(2d, 16d), SmallRectangleColor);
        DrawCenterRectangle(dc, point2, new Size(2d, 16d), SmallRectangleColor);
        DrawCenterRectangle(dc, point3, new Size(2d, 16d), SmallRectangleColor);
        DrawCenterRectangle(dc, point4, new Size(4d, 18d), LargeRectangleColor);

        // 水平线
        dc.DrawRectangle(LargeRectangleColor, null, new Rect(point0.X, point0.Y - 1.5d, length, 3d));

        // 画圆形拖拽按钮
        var points = new[] { point0, point1, point2, point3, point4 };

        var renderValue = Math.Clamp(Value, 0, points.Length - 1);
        dc.DrawEllipse(ThumbFill, new Pen(ThumbStroke, ThumbStrokeLength), points[renderValue], ThumbRadius, ThumbRadius);
    }

    /// <summary>
    /// 画以 center 为中心，size 为大小，fill 为填充色的矩形
    /// </summary>
    private static void DrawCenterRectangle(DrawingContext dc, Point center, Size size, Brush fill)
    {
        var rect = new Rect
        {
            X = center.X - size.Width / 2,
            Y = center.Y - size.Height / 2,
            Width = size.Width,
            Height = size.Height
        };

        dc.DrawRectangle(fill, null, rect);
    }

    private const double DEFAULT_OPACITY = 0.7d;

    protected override void OnMouseEnter(MouseEventArgs e)
    {
        base.OnMouseEnter(e);
        Opacity = 1d;
    }

    protected override void OnMouseLeave(MouseEventArgs e)
    {
        base.OnMouseLeave(e);
        Opacity = DEFAULT_OPACITY;

        if (IsMouseDown)
        {
            ReleaseMouseCapture();
            IsMouseDown = false;
        }
    }

    private bool IsMouseDown;


    protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
    {
        base.OnMouseLeftButtonDown(e);
        if (e.Handled) return;

        CaptureMouse();
        IsMouseDown = true;
        UpdateValue(e);
    }

    protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
    {
        base.OnMouseLeftButtonUp(e);
        if (e.Handled) return;
        if (!IsMouseDown) return;

        ReleaseMouseCapture();
        IsMouseDown = false;
    }

    protected override void OnMouseMove(MouseEventArgs e)
    {
        base.OnMouseMove(e);
        if (e.Handled) return;
        if (!IsMouseDown) return;

        UpdateValue(e);
    }

    private void UpdateValue(MouseEventArgs e)
    {
        var position = e.GetPosition(this).X;
        var length = ActualWidth - ThumbRadius * 2;

        if (position <= ThumbRadius + 0.125 * length)
        {
            Value = 0;
        }
        else if (position <= ThumbRadius + 0.375 * length)
        {
            Value = 1;
        }
        else if (position <= ThumbRadius + 0.625 * length)
        {
            Value = 2;
        }
        else if (position <= ThumbRadius + 0.875 * length)
        {
            Value = 3;
        }
        else
        {
            Value = 4;
        }
    }
}